Design Coffee Vending Machine

Last Updated: December 18, 2025

Ashish

Ashish Pratap Singh

medium

In this chapter, we will explore the low-level design of a coffee vending machine in detail.

Lets start by clarifying the requirements:

1. Clarifying Requirements

Before starting the design, it's important to ask thoughtful questions to uncover hidden assumptions and better define the scope of the system.

Here is an example of how a conversation between the candidate and the interviewer might unfold:

With the scope clarified, we can now summarize the core system requirements.

1.1 Functional Requirements

  • Support a configurable list of beverage types (e.g., espresso, cappuccino, latte)
  • Allow adding/updating the ingredient stock
  • Allow users to select a beverage and customize basic options such as sugar and milk levels
  • Deduct the appropriate amount of ingredients from inventory after each successful order.
  • Display an appropriate message if a selected beverage cannot be prepared due to insufficient ingredients.
  • Serve one customer at a time (no concurrency required)

1.2 Non-Functional Requirements

  • Modularity: The system should have clear separation of concerns
  • Extensibility: The design should support adding new drink types, and customizing ingredient mixes
  • Maintainability: The codebase should follow object-oriented principles and allow easy modification or extension
  • User Feedback: The machine should provide clear instructions and status updates to the user throughout the interaction

2. Identifying Core Entities

Core entities are the fundamental building blocks of our system. We identify them by analyzing key nouns (e.g., beverage, ingredient, payment, inventory, customization) and actions (e.g., select, pay, prepare, refill, notify) from the functional requirements. These typically translate into classes, enums, or interfaces in an object-oriented design.

Let’s walk through the requirements and extract the relevant entities:

1. Support a configurable list of beverage types (e.g., espresso, cappuccino, latte).

This points directly to a Coffee entity (an abstract base class) representing a generic beverage. Concrete subclasses like EspressoLatte, and Cappuccino define specific coffee types.

2. Allow users to customize basic options (sugar, milk) per beverage.

The ability to dynamically add features like sugar or caramel syrup without altering the base Coffee class is a classic use case for the Decorator pattern. This introduces a CoffeeDecorator abstract class and concrete decorator classes like ExtraSugarDecorator and CaramelSyrupDecorator, which wrap Coffee objects to add customization. ToppingType enum helps specify these options.

3. Deduct ingredients from inventory and display messages if unavailable.

This necessitates an Inventory entity to manage the stock levels of various raw materials. The raw materials themselves are represented by the Ingredient enum (COFFEE_BEANS, MILK, SUGAR, etc.). The Inventory is implemented as a Singleton to ensure a single, consistent view of stock.

4. Serve one customer at a time, with specific interaction flows (selection, dispensing).

The overall control and flow of the vending machine's operations are managed by the CoffeeVendingMachine entity.

These core entities define the essential abstractions of a Coffee Vending Machine and will guide the structure of your low-level design and class diagrams.

3. Designing Classes and Relationships

This section breaks down the system's architecture into its fundamental classes, their responsibilities, and the relationships that connect them. We also explore the key design patterns that provide robustness and flexibility to the solution.

3.1 Class Definitions

The system is composed of several types of classes, each with a distinct role.

Enums

Enums
  • CoffeeType: Defines the base types of coffee available (ESPRESSO, LATTE, CAPPUCCINO).
  • Ingredient: Represents all raw materials managed by the inventory (COFFEE_BEANS, MILK, etc.).
  • ToppingType: Defines the optional add-ons a user can select (EXTRA_SUGAR, CARAMEL_SYRUP).

Data Classes

This design does not use simple data classes, as most objects encapsulate both state and behavior.

Core Classes

Coffee (Abstract Class)

The base class for all beverage products.

Coffee

It defines the skeleton of the preparation algorithm using the Template Method pattern, with a core prepare() method and an abstract addCondiments() "hook" for subclasses to implement.

  • Espresso, Latte, Cappuccino: Concrete implementations of Coffee. Each class provides a specific implementation for addCondiments(), along with its unique price and recipe.

CoffeeFactory

A simple factory class responsible for creating instances of concrete Coffee types based on a CoffeeType enum.

Inventory (Singleton)

Inventory

A thread-safe class that manages the stock levels of all Ingredients. It provides a single, global point of access to the machine's physical inventory.

CoffeeVendingMachine (Singleton & Facade)

CoffeeVendingMachine

The main class and the primary entry point for all client interactions. It acts as the Context for the State pattern, delegating all user actions to its current state object. It also acts as a Facade, simplifying the complex process of coffee creation and dispensing for the client.

3.2 Class Relationships

The relationships between classes define the system's structure and data flow.

Inheritance / Implementation

  • Espresso, Latte, Cappuccino, and the abstract CoffeeDecorator all extend the Coffee abstract class.
  • ExtraSugarDecorator and CaramelSyrupDecorator extend the CoffeeDecorator abstract class.
  • Concrete state classes like ReadyState and SelectingState implement the VendingMachineState interface.

Composition

  • The CoffeeVendingMachine "has-a" VendingMachineState object that defines its current behavior.
  • A CoffeeDecorator object is composed of another Coffee object (the one it wraps), forming a recursive structure.

Association

  • The CoffeeVendingMachine is associated with the Coffee object that the user has selected.

Dependency

  • The CoffeeVendingMachine (client) depends on the CoffeeFactory to create base coffee objects.
  • The CoffeeVendingMachine depends on concrete CoffeeDecorators to add toppings.
  • The CoffeeVendingMachine depends on the Inventory singleton to check for and deduct ingredients.
  • All concrete VendingMachineStates depend on the CoffeeVendingMachine (the context) to access machine data and trigger state transitions.

3.3 Key Design Patterns

State Pattern

The lifecycle of a user transaction is managed using the State pattern.

VendingMachineState

The CoffeeVendingMachine (Context) delegates its behavior to different VendingMachineState objects (ReadyState, SelectingState, etc.). This cleanly separates state-specific logic and makes managing the user interaction flow robust and easy to extend.

Decorator Pattern

CoffeeDecorator

This pattern is used to add toppings to a coffee dynamically. The CoffeeDecorator classes wrap a base Coffee object (or another decorator), allowing for flexible combinations of toppings. Each decorator adds its own cost, recipe ingredients, and preparation steps without altering the base coffee classes.

Template Method Pattern

The abstract Coffee class defines the prepare() method, which serves as a template for making any coffee. It standardizes the algorithm (grind, brew, pour) while allowing subclasses (Latte, Cappuccino) to provide their own implementation for the addCondiments() step.

Factory Pattern (Simple Factory)

The CoffeeFactory encapsulates the logic for creating different types of Coffee. This decouples the CoffeeVendingMachine from the instantiation of concrete coffee classes, making it easy to add new coffee types in the future.

Facade Pattern

The CoffeeVendingMachine class acts as a facade. It provides a simple, high-level API (selectCoffee, insertMoney, dispenseCoffee) that hides the complex internal interactions between the factory, decorators, states, and inventory from the client.

Singleton Pattern

CoffeeVendingMachine and Inventory are implemented as singletons. This is a logical choice as it models a single physical machine with a single, shared inventory, ensuring a global point of access and control.

3.4 Full Class Diagram

Coffee Vending Machine Class Diagram

4. Implementation

4.1 Enums

1class CoffeeType(Enum):
2    ESPRESSO = "ESPRESSO"
3    LATTE = "LATTE"
4    CAPPUCCINO = "CAPPUCCINO"
5
6
7class Ingredient(Enum):
8    COFFEE_BEANS = "COFFEE_BEANS"
9    MILK = "MILK"
10    SUGAR = "SUGAR"
11    WATER = "WATER"
12    CARAMEL_SYRUP = "CARAMEL_SYRUP"
13
14
15class ToppingType(Enum):
16    EXTRA_SUGAR = "EXTRA_SUGAR"
17    CARAMEL_SYRUP = "CARAMEL_SYRUP"
  • CoffeeType: Defines the base beverages.
  • Ingredient: Inventory-managed raw materials.
  • ToppingType: Optional add-ons for customization.

4.2 Coffee (Template Method Pattern)

This pattern defines the skeleton of an algorithm in a base class, deferring some steps to subclasses. This is perfect for coffee preparation, where the core steps are the same, but the condiments vary.

Coffee class defines the template method prepare() and the abstract addCondiments() step.

1class Coffee(ABC):
2    def __init__(self):
3        self.coffee_type = "Unknown Coffee"
4    
5    def get_coffee_type(self) -> str:
6        return self.coffee_type
7    
8    # The Template Method
9    def prepare(self):
10        print(f"\nPreparing your {self.get_coffee_type()}...")
11        self._grind_beans()
12        self._brew()
13        self.add_condiments()  # The "hook" for base coffee types
14        self._pour_into_cup()
15        print(f"{self.get_coffee_type()} is ready!")
16    
17    # Common steps
18    def _grind_beans(self):
19        print("- Grinding fresh coffee beans.")
20    
21    def _brew(self):
22        print("- Brewing coffee with hot water.")
23    
24    def _pour_into_cup(self):
25        print("- Pouring into a cup.")
26    
27    # Abstract step to be implemented by subclasses
28    @abstractmethod
29    def add_condiments(self):
30        pass
31    
32    @abstractmethod
33    def get_price(self) -> int:
34        pass
35    
36    @abstractmethod
37    def get_recipe(self) -> Dict[Ingredient, int]:
38        pass

Implements the Template Method pattern for beverage preparation, allowing subclasses to override addCondiments().

The prepare() method is marked final (implicitly in this structure) to ensure subclasses cannot override the overall preparation sequence.

The addCondiments() method is the "hook" where subclasses can insert their unique logic (like adding milk for a latte) into the predefined algorithm. This promotes code reuse for the common steps.

4.3 Concrete Coffee Types

Each subclass provides its price, recipe, and custom condiments.

1class Espresso(Coffee):
2    def __init__(self):
3        super().__init__()
4        self.coffee_type = "Espresso"
5    
6    def add_condiments(self):
7        pass  # No extra condiments for espresso
8    
9    def get_price(self) -> int:
10        return 150
11    
12    def get_recipe(self) -> Dict[Ingredient, int]:
13        return {Ingredient.COFFEE_BEANS: 7, Ingredient.WATER: 30}
14
15class Cappuccino(Coffee):
16    def __init__(self):
17        super().__init__()
18        self.coffee_type = "Cappuccino"
19    
20    def add_condiments(self):
21        print("- Adding steamed milk and foam.")
22    
23    def get_price(self) -> int:
24        return 250
25    
26    def get_recipe(self) -> Dict[Ingredient, int]:
27        return {Ingredient.COFFEE_BEANS: 7, Ingredient.WATER: 30, Ingredient.MILK: 100}
28
29class Latte(Coffee):
30    def __init__(self):
31        super().__init__()
32        self.coffee_type = "Latte"
33    
34    def add_condiments(self):
35        print("- Adding steamed milk.")
36    
37    def get_price(self) -> int:
38        return 220
39    
40    def get_recipe(self) -> Dict[Ingredient, int]:
41        return {Ingredient.COFFEE_BEANS: 7, Ingredient.WATER: 30, Ingredient.MILK: 150}

4.4 CoffeeFactory

Implements the Factory pattern to abstract coffee object creation.

1class CoffeeFactory:
2    @staticmethod
3    def create_coffee(coffee_type: CoffeeType) -> Coffee:
4        if coffee_type == CoffeeType.ESPRESSO:
5            return Espresso()
6        elif coffee_type == CoffeeType.LATTE:
7            return Latte()
8        elif coffee_type == CoffeeType.CAPPUCCINO:
9            return Cappuccino()
10        else:
11            raise ValueError(f"Unsupported coffee type: {coffee_type}")

4.5 CoffeeDecorator and Topping Decorators

Implements the Decorator pattern to layer toppings dynamically. Each decorator adjusts the recipe and final preparation behavior.

1class CoffeeDecorator(Coffee):
2    def __init__(self, coffee: Coffee):
3        super().__init__()
4        self.decorated_coffee = coffee
5    
6    def get_price(self) -> int:
7        return self.decorated_coffee.get_price()
8    
9    def get_recipe(self) -> Dict[Ingredient, int]:
10        return self.decorated_coffee.get_recipe()
11    
12    def add_condiments(self):
13        self.decorated_coffee.add_condiments()
14    
15    def prepare(self):
16        self.decorated_coffee.prepare()
17
18class CaramelSyrupDecorator(CoffeeDecorator):
19    COST = 30
20    RECIPE_ADDITION = {Ingredient.CARAMEL_SYRUP: 10}
21    
22    def __init__(self, coffee: Coffee):
23        super().__init__(coffee)
24    
25    def get_coffee_type(self) -> str:
26        return self.decorated_coffee.get_coffee_type() + ", Caramel Syrup"
27    
28    def get_price(self) -> int:
29        return self.decorated_coffee.get_price() + self.COST
30    
31    def get_recipe(self) -> Dict[Ingredient, int]:
32        new_recipe = self.decorated_coffee.get_recipe().copy()
33        for ingredient, qty in self.RECIPE_ADDITION.items():
34            new_recipe[ingredient] = new_recipe.get(ingredient, 0) + qty
35        return new_recipe
36    
37    def prepare(self):
38        # First, prepare the underlying coffee
39        super().prepare()
40        # Then, add the specific step for this decorator
41        print("- Drizzling Caramel Syrup on top.")
42
43class ExtraSugarDecorator(CoffeeDecorator):
44    COST = 10
45    RECIPE_ADDITION = {Ingredient.SUGAR: 1}
46    
47    def __init__(self, coffee: Coffee):
48        super().__init__(coffee)
49    
50    def get_coffee_type(self) -> str:
51        return self.decorated_coffee.get_coffee_type() + ", Extra Sugar"
52    
53    def get_price(self) -> int:
54        return self.decorated_coffee.get_price() + self.COST
55    
56    def get_recipe(self) -> Dict[Ingredient, int]:
57        new_recipe = self.decorated_coffee.get_recipe().copy()
58        for ingredient, qty in self.RECIPE_ADDITION.items():
59            new_recipe[ingredient] = new_recipe.get(ingredient, 0) + qty
60        return new_recipe
61    
62    def prepare(self):
63        super().prepare()
64        print("- Stirring in Extra Sugar.")

Decorators allow for flexible combinations. A client can create a Latte, wrap it with ExtraSugarDecorator, and then wrap that result with CaramelSyrupDecorator. The final object will have the combined price, recipe, and preparation steps of all components.

4.7 VendingMachineState Interface and Concrete States

Implements the State pattern to handle user interaction flow:

  • Selection → Payment → Dispensing → Reset
1class VendingMachineState(ABC):
2    @abstractmethod
3    def select_coffee(self, machine: 'CoffeeVendingMachine', coffee: Coffee):
4        pass
5    
6    @abstractmethod
7    def insert_money(self, machine: 'CoffeeVendingMachine', amount: int):
8        pass
9    
10    @abstractmethod
11    def dispense_coffee(self, machine: 'CoffeeVendingMachine'):
12        pass
13    
14    @abstractmethod
15    def cancel(self, machine: 'CoffeeVendingMachine'):
16        pass
17
18
19class ReadyState(VendingMachineState):
20    def select_coffee(self, machine: 'CoffeeVendingMachine', coffee: Coffee):
21        machine.set_selected_coffee(coffee)
22        machine.set_state(SelectingState())
23        print(f"{coffee.get_coffee_type()} selected. Price: {coffee.get_price()}")
24    
25    def insert_money(self, machine: 'CoffeeVendingMachine', amount: int):
26        print("Please select a coffee first.")
27    
28    def dispense_coffee(self, machine: 'CoffeeVendingMachine'):
29        print("Please select and pay first.")
30    
31    def cancel(self, machine: 'CoffeeVendingMachine'):
32        print("Nothing to cancel.")
33
34
35class SelectingState(VendingMachineState):
36    def select_coffee(self, machine: 'CoffeeVendingMachine', coffee: Coffee):
37        print("Already selected. Please pay or cancel.")
38    
39    def insert_money(self, machine: 'CoffeeVendingMachine', amount: int):
40        machine.set_money_inserted(machine.get_money_inserted() + amount)
41        print(f"Inserted {amount}. Total: {machine.get_money_inserted()}")
42        if machine.get_money_inserted() >= machine.get_selected_coffee().get_price():
43            machine.set_state(PaidState())
44    
45    def dispense_coffee(self, machine: 'CoffeeVendingMachine'):
46        print("Please insert enough money first.")
47    
48    def cancel(self, machine: 'CoffeeVendingMachine'):
49        print(f"Transaction cancelled. Refunding {machine.get_money_inserted()}")
50        machine.reset()
51        machine.set_state(ReadyState())
52
53
54class PaidState(VendingMachineState):
55    def select_coffee(self, machine: 'CoffeeVendingMachine', coffee: Coffee):
56        print("Already paid. Please dispense or cancel.")
57    
58    def insert_money(self, machine: 'CoffeeVendingMachine', amount: int):
59        machine.set_money_inserted(machine.get_money_inserted() + amount)
60        print(f"Additional {amount} inserted. Total: {machine.get_money_inserted()}")
61    
62    def dispense_coffee(self, machine: 'CoffeeVendingMachine'):
63        inventory = Inventory.get_instance()
64        coffee = machine.get_selected_coffee()
65        
66        if not inventory.has_ingredients(coffee.get_recipe()):
67            print("Sorry, we are out of ingredients. Refunding your money.")
68            print(f"Refunding {machine.get_money_inserted()}")
69            machine.reset()
70            machine.set_state(OutOfIngredientState())
71            return
72        
73        # Deduct ingredients and prepare coffee
74        inventory.deduct_ingredients(coffee.get_recipe())
75        coffee.prepare()
76        
77        # Calculate change
78        change = machine.get_money_inserted() - coffee.get_price()
79        if change > 0:
80            print(f"Here's your change: {change}")
81        
82        machine.reset()
83        machine.set_state(ReadyState())
84    
85    def cancel(self, machine: 'CoffeeVendingMachine'):
86        print(f"Transaction cancelled. Refunding {machine.get_money_inserted()}")
87        machine.reset()
88        machine.set_state(ReadyState())
89
90
91class OutOfIngredientState(VendingMachineState):
92    def select_coffee(self, machine: 'CoffeeVendingMachine', coffee: Coffee):
93        print("Sorry, we are sold out.")
94    
95    def insert_money(self, machine: 'CoffeeVendingMachine', amount: int):
96        print("Sorry, we are sold out. Money refunded.")
97    
98    def dispense_coffee(self, machine: 'CoffeeVendingMachine'):
99        print("Sorry, we are sold out.")
100    
101    def cancel(self, machine: 'CoffeeVendingMachine'):
102        print(f"Refunding {machine.get_money_inserted()}")
103        machine.reset()
104        machine.set_state(ReadyState())

Each state class handles user actions appropriately. In ReadyState, only selectCoffee is valid. In SelectingState, insertMoney and cancel are valid. This eliminates a massive if/else or switch block in the main machine class.

Inventory

Manages the stock levels of all ingredients.

1class Inventory:
2    _instance = None
3    _lock = threading.Lock()
4    
5    def __new__(cls):
6        if cls._instance is None:
7            with cls._lock:
8                if cls._instance is None:
9                    cls._instance = super().__new__(cls)
10                    cls._instance._initialized = False
11        return cls._instance
12    
13    def __init__(self):
14        if not self._initialized:
15            self._stock: Dict[Ingredient, int] = {}
16            self._lock = threading.Lock()
17            self._initialized = True
18    
19    @classmethod
20    def get_instance(cls):
21        return cls()
22    
23    def add_stock(self, ingredient: Ingredient, quantity: int):
24        self._stock[ingredient] = self._stock.get(ingredient, 0) + quantity
25    
26    def has_ingredients(self, recipe: Dict[Ingredient, int]) -> bool:
27        return all(self._stock.get(ingredient, 0) >= quantity 
28                  for ingredient, quantity in recipe.items())
29    
30    def deduct_ingredients(self, recipe: Dict[Ingredient, int]):
31        with self._lock:
32            if not self.has_ingredients(recipe):
33                print("Not enough ingredients to make coffee.")
34                return
35            
36            for ingredient, quantity in recipe.items():
37                self._stock[ingredient] -= quantity
38    
39    def print_inventory(self):
40        print("--- Current Inventory ---")
41        for ingredient, quantity in self._stock.items():
42            print(f"{ingredient.value}: {quantity}")
43        print("-------------------------")
  • Singleton Pattern: A single Inventory instance is shared across the entire application, representing the physical inventory of the machine.

4.8 CoffeeVendingMachine (Singleton + Context)

This is the main class that clients interact with.

1class CoffeeVendingMachine:
2    _instance = None
3    _lock = threading.Lock()
4    
5    def __new__(cls):
6        if cls._instance is None:
7            with cls._lock:
8                if cls._instance is None:
9                    cls._instance = super().__new__(cls)
10                    cls._instance._initialized = False
11        return cls._instance
12    
13    def __init__(self):
14        if not self._initialized:
15            self._state = ReadyState()
16            self._selected_coffee: Coffee = None
17            self._money_inserted = 0
18            self._initialized = True
19    
20    @classmethod
21    def get_instance(cls):
22        return cls()
23    
24    def select_coffee(self, coffee_type: CoffeeType, toppings: List[ToppingType]):
25        # 1. Create the base coffee using the factory
26        coffee = CoffeeFactory.create_coffee(coffee_type)
27        
28        # 2. Wrap it with decorators
29        for topping in toppings:
30            if topping == ToppingType.EXTRA_SUGAR:
31                coffee = ExtraSugarDecorator(coffee)
32            elif topping == ToppingType.CARAMEL_SYRUP:
33                coffee = CaramelSyrupDecorator(coffee)
34        
35        # Let the state handle the rest
36        self._state.select_coffee(self, coffee)
37    
38    def insert_money(self, amount: int):
39        self._state.insert_money(self, amount)
40    
41    def dispense_coffee(self):
42        self._state.dispense_coffee(self)
43    
44    def cancel(self):
45        self._state.cancel(self)
46    
47    # Getters and Setters used by State objects
48    def set_state(self, state: VendingMachineState):
49        self._state = state
50    
51    def get_state(self) -> VendingMachineState:
52        return self._state
53    
54    def set_selected_coffee(self, coffee: Coffee):
55        self._selected_coffee = coffee
56    
57    def get_selected_coffee(self) -> Coffee:
58        return self._selected_coffee
59    
60    def set_money_inserted(self, amount: int):
61        self._money_inserted = amount
62    
63    def get_money_inserted(self) -> int:
64        return self._money_inserted
65    
66    def reset(self):
67        self._selected_coffee = None
68        self._money_inserted = 0
69

The machine provides a simple, high-level API (selectCoffee, insertMoney) that hides the internal complexity of factories, decorators, states, and inventory.

4.9 CoffeeVendingMachineDemo

The demo class validates the entire system by simulating various user scenarios.

1class CoffeeVendingMachineDemo:
2    @staticmethod
3    def main():
4        machine = CoffeeVendingMachine.get_instance()
5        inventory = Inventory.get_instance()
6        
7        # Initial setup: Refill inventory
8        print("=== Initializing Vending Machine ===")
9        inventory.add_stock(Ingredient.COFFEE_BEANS, 50)
10        inventory.add_stock(Ingredient.WATER, 500)
11        inventory.add_stock(Ingredient.MILK, 200)
12        inventory.add_stock(Ingredient.SUGAR, 100)
13        inventory.add_stock(Ingredient.CARAMEL_SYRUP, 50)
14        inventory.print_inventory()
15        
16        # Scenario 1: Successful Purchase of a Latte
17        print("\n--- SCENARIO 1: Buy a Latte (Success) ---")
18        machine.select_coffee(CoffeeType.LATTE, [])
19        machine.insert_money(200)
20        machine.insert_money(50)  # Total 250, price is 220
21        machine.dispense_coffee()
22        inventory.print_inventory()
23        
24        # Scenario 2: Purchase with Insufficient Funds & Cancellation
25        print("\n--- SCENARIO 2: Buy Espresso (Insufficient Funds & Cancel) ---")
26        machine.select_coffee(CoffeeType.ESPRESSO, [])
27        machine.insert_money(100)  # Price is 150
28        machine.dispense_coffee()  # Should fail
29        machine.cancel()  # Should refund 100
30        inventory.print_inventory()  # Should be unchanged
31        
32        # Scenario 3: Attempt to Buy with Insufficient Ingredients
33        print("\n--- SCENARIO 3: Buy Cappuccino (Out of Milk) ---")
34        inventory.print_inventory()
35        machine.select_coffee(CoffeeType.CAPPUCCINO, [ToppingType.CARAMEL_SYRUP, ToppingType.EXTRA_SUGAR])
36        machine.insert_money(300)
37        machine.dispense_coffee()  # Should fail and refund
38        inventory.print_inventory()
39        
40        # Refill and final test
41        print("\n--- REFILLING AND FINAL TEST ---")
42        inventory.add_stock(Ingredient.MILK, 200)
43        inventory.print_inventory()
44        machine.select_coffee(CoffeeType.LATTE, [ToppingType.CARAMEL_SYRUP])
45        machine.insert_money(250)
46        machine.dispense_coffee()
47        inventory.print_inventory()
48
49if __name__ == "__main__":
50    CoffeeVendingMachineDemo.main()

5. Run and Test

Files19
decorators
enums
factory
states
templatemethod
coffee_vending_machine_demo.py
main
coffee_vending_machine.py
inventory.py
coffee_vending_machine_demo.pymain
Output

6. Quiz

Design Coffee Vending Machine - Quiz

1 / 20
Multiple Choice

Which responsibility is BEST handled by the Inventory entity in a coffee vending machine design?

How helpful was this article?

Comments


0/2000

No comments yet. Be the first to comment!

Copilot extension content script